/**
 * 关系运算符
 *   > < >= <= == !=
 * 
 * 最佳实践
 *   不要向 if 语句添加不必要的 == 或 !=。它使它们更难以阅读而不提供任何附加价值。
 *   if (b1 == true)  =>  if (b1)
 *   if (b1 == false) =>  if (!b1)
 * 
 * 计算浮点值的比较可能会出现问题
 *   使用任何关系运算符比较浮点值都可能很危险。这是因为浮点值并不精确，浮点操作数中的小舍入误差可能会导致它们比预期稍小或稍大。
 * 
 * 如果有可能计算出这些值，请避免使用运算符 == 和运算符！= 来比较浮点值。
 * 
 * 比较浮点数
 * 
 */

#include <iostream>
#include <cmath> // for std::abs()
#include <algorithm> // for std::max

// 自己的“足够接近”的函数
// 这种写法其实不太好
// absEpsilon is an absolute value
bool approximatelyEqualAbs(double a, double b, double absEpsilon)
{
    // if the distance between a and b is less than or equal to absEpsilon, then a and b are "close enough"
    return std::abs(a - b) <= absEpsilon;
}

// 这种比较方法比较合适
// “足够接近”意味着a和b与a和b中较大者的误差在 1% 以内，则我们传入 relEpsilon 0.01 (1% = 1/100 = 0.01)
// Return true if the difference between a and b is within epsilon percent of the larger of a and b
bool approximatelyEqualRel(double a, double b, double relEpsilon)
{
	return (std::abs(a - b) <= (std::max(std::abs(a), std::abs(b)) * relEpsilon));
}

int main()
{
    std::cout << "Enter an integer: ";
    int x{};
    std::cin >> x;

    std::cout << "Enter another integer: ";
    int y{};
    std::cin >> y;

    if (x == y)
        std::cout << x << " equals " << y << '\n';
    if (x != y)
        std::cout << x << " does not equal " << y << '\n';
    if (x > y)
        std::cout << x << " is greater than " << y << '\n';
    if (x < y)
        std::cout << x << " is less than " << y << '\n';
    if (x >= y)
        std::cout << x << " is greater than or equal to " << y << '\n';
    if (x <= y)
        std::cout << x << " is less than or equal to " << y << '\n';


    double d1{ 100.0 - 99.99 }; // should equal 0.01 mathematically
    double d2{ 10.0 - 9.99 }; // should equal 0.01 mathematically

    if (d1 == d2)
        std::cout << "d1 == d2" << '\n';
    else if (d1 > d2)
        std::cout << "d1 > d2" << '\n';
    else if (d1 < d2)
        std::cout << "d1 < d2" << '\n';

    return 0;
}



// 浮点数比较大小
// Prior to C++23 version

// #include <algorithm> // for std::max
// #include <iostream>

// // Our own constexpr implementation of std::abs (for use prior to C++23)
// // In C++23, use std::abs
// // constAbs() can be called like a normal function, but can handle different types of values (e.g. int, double, etc...)
// template <typename T>
// constexpr T constAbs(T x)
// {
//     return (x < 0 ? -x : x);
// }

// // Return true if the difference between a and b is within epsilon percent of the larger of a and b
// constexpr bool approximatelyEqualRel(double a, double b, double relEpsilon)
// {
//     return (constAbs(a - b) <= (std::max(constAbs(a), constAbs(b)) * relEpsilon));
// }

// // Return true if the difference between a and b is less than or equal to absEpsilon, or within relEpsilon percent of the larger of a and b
// constexpr bool approximatelyEqualAbsRel(double a, double b, double absEpsilon, double relEpsilon)
// {
//     // Check if the numbers are really close -- needed when comparing numbers near zero.
//     if (constAbs(a - b) <= absEpsilon)
//         return true;

//     // Otherwise fall back to Knuth's algorithm
//     return approximatelyEqualRel(a, b, relEpsilon);
// }

// int main()
// {
//     // a is really close to 1.0, but has rounding errors
//     constexpr double a{ 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 };

//     constexpr double relEps { 1e-8 };
//     constexpr double absEps { 1e-12 };

//     constexpr bool same { approximatelyEqualAbsRel(a, 1.0, absEps, relEps) };
//     std::cout << same << '\n';

//     return 0;
// }